package com.yuandian.management.service.impl;

import com.baomidou.mybatisplus.core.conditions.query.LambdaQueryWrapper;
import com.baomidou.mybatisplus.core.conditions.query.QueryWrapper;
import com.baomidou.mybatisplus.core.conditions.update.LambdaUpdateWrapper;
import com.baomidou.mybatisplus.core.toolkit.Wrappers;
import com.baomidou.mybatisplus.extension.plugins.pagination.Page;
import com.yuandian.api.management.entity.*;
import com.yuandian.api.management.enums.GraphType;
import com.yuandian.bpm.common.core.util.R;
import com.yuandian.bpm.common.security.util.SecurityUtils;
import com.yuandian.constant.Constants;
import com.yuandian.management.service.*;
import com.yuandian.management.vo.ITRoadVo;
import lombok.RequiredArgsConstructor;
import lombok.extern.slf4j.Slf4j;
import org.springframework.beans.BeanUtils;
import org.springframework.stereotype.Service;
import org.springframework.transaction.annotation.Transactional;
import org.springframework.util.CollectionUtils;

import java.time.LocalDateTime;
import java.time.format.DateTimeFormatter;
import java.util.*;
import java.util.stream.Collectors;

/**
 * 说明：通用接口配置服务实现
 * @Author zfsn
 * @Date 2023/2/20 19:59
 */
@Slf4j
@Service
@RequiredArgsConstructor
public class ItRoadMapServiceImpl implements ITRoadMapService {

	private final ConfSegmentService confSegmentService;

	private final ConfGraphService confGraphService;

	private final ConfComponentIpService confComponentIpService;

	private final ConfComponentResourceService confComponentResourceService;

	private final ConfNodePropertyService confNodePropertyService;

	private final ConfSystemService confSystemService;

	private final ConfUnconfirmedUrlService unconfirmedUrlService;

	private final ConfConfirmedUrlService confConfirmedUrlService;

	private final ConfResourceService confResourceService;

	private final ConfSegmentResourceRelationService segmentResourceRelationService;

	/**
	 * 通过系统id 获取it路径图
	 *
	 * @param systemId 系统id
	 * @return 通用返回对象
	 */
	@Override
	@Transactional(rollbackFor = Exception.class)
	public List<Map<String, Object>> getRoadMap(Integer systemId) {

		// 1. 获取网端信息
		QueryWrapper<ConfSegment> queryWrapper = new QueryWrapper<>();
		queryWrapper.eq("system_id", systemId);
		Map<Integer, String> confSegmentsMap = confSegmentService.list(queryWrapper).stream().collect(Collectors.toMap(ConfSegment::getId, ConfSegment::getName));

		// 2. 获取节点关系信息
		QueryWrapper<ConfGraph> queryWrapperGraph = new QueryWrapper<>();
		queryWrapperGraph.eq("graph_id", systemId);
		queryWrapperGraph.eq("type", GraphType.IT_ROAD_RELATIONSHIP.getType());
		List<ConfGraph> confGraphs = confGraphService.list(queryWrapperGraph);

		// 2. 获取节点ip和端口
		QueryWrapper<ConfComponentIp> queryWrapperComponentIp = new QueryWrapper<>();
		queryWrapperComponentIp.eq("system_id", systemId);
		List<ConfComponentIp> confComponentIps = confComponentIpService.list(queryWrapperComponentIp);


		// 4. 获取节点坐标等信息
		LambdaQueryWrapper<ConfNodeProperty> propertyLambdaQueryWrapper = Wrappers.lambdaQuery();
		propertyLambdaQueryWrapper.eq(ConfNodeProperty::getType, GraphType.IT_ROAD_RELATIONSHIP.getType());
		propertyLambdaQueryWrapper.eq(ConfNodeProperty::getGraphId, systemId);
		Map<String, ConfNodeProperty> nodePropertyIdAndObjectMap = confNodePropertyService.list(propertyLambdaQueryWrapper).stream().collect(Collectors.toMap(ConfNodeProperty::getNodeId, v -> v, (k1, k2) -> k2));

		if (nodePropertyIdAndObjectMap.size() == 0) {
			return new ArrayList<>();
		}
		// 将上面信息组装成 多节点的树结构, 返回给前端
		return generateRoadMap(confComponentIps, confGraphs, confSegmentsMap, nodePropertyIdAndObjectMap, systemId);
	}

	/**
	 * 增加节点
	 *
	 * @param confSegment
	 * @return 通用返回对象
	 */
	@Override
	@Transactional(rollbackFor = Exception.class)
	public R<String> addNode(ITRoadVo confSegment) {
		// 1. 保存网端信息
		confSegment.setCreateBy(SecurityUtils.getUser().getName());
		confSegment.setCreateTime(LocalDateTime.now().format(DateTimeFormatter.ofPattern(Constants.YYYY_MM_DD_HH_MM_SS)));
		confSegmentService.save(confSegment);
		LambdaQueryWrapper<ConfSegment> queryWrapper = Wrappers.lambdaQuery();
		queryWrapper.eq(ConfSegment::getSystemId, confSegment.getSystemId());
		queryWrapper.eq(ConfSegment::getName, confSegment.getName());
		queryWrapper.eq(ConfSegment::getProtocolCode, confSegment.getProtocolCode());
		queryWrapper.eq(ConfSegment::getSign, confSegment.getSign());
		queryWrapper.eq(ConfSegment::getType, confSegment.getType());
		queryWrapper.eq(ConfSegment::getCreateBy, confSegment.getCreateBy());
		queryWrapper.eq(ConfSegment::getCreateTime, confSegment.getCreateTime());
		ConfSegment segment = confSegmentService.getOneByWrapper(queryWrapper);

		//2. 保存节点位置坐标等信息
		ConfNodeProperty confNodeProperty = new ConfNodeProperty();
		confNodeProperty.setType(GraphType.IT_ROAD_RELATIONSHIP.getType());
		confNodeProperty.setGraphId(String.valueOf(confSegment.getSystemId()));
		confNodeProperty.setNodeId(String.valueOf(segment.getId()));
		confNodeProperty.setLocationX(confSegment.getLocationX());
		confNodeProperty.setLocationY(confSegment.getLocationY());
		confNodeProperty.setCreateBy(SecurityUtils.getUser().getName());
		confNodeProperty.setCreateTime(LocalDateTime.now());
		return R.ok(confNodePropertyService.save(confNodeProperty) ? "增加节点成功": "增加节点失败");
	}

	/**
	 * 增加节点连线
	 *
	 * @param confGraph
	 * @return 通用返回对象
	 */
	@Override
	public R<String> addLink(ConfGraph confGraph) {
		if(hasCircle(confGraph)){
			return R.failed("存在环,该资源不能够进行添加");
		}
		confGraph.setType(GraphType.IT_ROAD_RELATIONSHIP.getType());
		confGraph.setGraphId(String.valueOf(confGraph.getSystemId()));
		confGraph.setCreateBy(SecurityUtils.getUser().getName());
		confGraph.setCreateTime(LocalDateTime.now());
		return R.ok(confGraphService.save(confGraph) ? "增加节点连线成功": "增加节点连线失败");
	}

	/**
	 * 判断节点之间是否存在环
	 * @param confGraph
	 * @return
	 */
	private boolean hasCircle(ConfGraph confGraph) {
		LambdaQueryWrapper<ConfGraph> queryWrapper = Wrappers.lambdaQuery();
		queryWrapper.eq(ConfGraph::getType, GraphType.IT_ROAD_RELATIONSHIP.getType())
					.eq(ConfGraph::getGraphId, String.valueOf(confGraph.getSystemId()));
		List<ConfGraph> confGraphs = confGraphService.list(queryWrapper);

		// 如果节点之间没有连接, 则认为节点之间没有形成环状
		if (CollectionUtils.isEmpty(confGraphs)) {
			return false;
		}
		confGraphs.add(confGraph);

		// 1. 统计每个节点的入度，并将入度为0的节点加入队列中
		Map<String, Integer> hashMap = new HashMap<>();
		Map<String, List<String>> map = new HashMap<>();
		for (ConfGraph node : confGraphs) {
			String id = node.getNodeId();
			String preId = node.getParentNodeId();
			map.computeIfAbsent(preId,k -> new ArrayList<>()).add(id);
			hashMap.put(id, hashMap.getOrDefault(id, 0) + 1);
		}
		Queue<String> queue = new LinkedList<>();
		for (String key : hashMap.keySet()) {
			if (hashMap.getOrDefault(key, 0) == 0){
				queue.offer(key);
			}
		}

		// 2. 对队列中的节点进行遍历，将其所有出边对应的节点的入度减1，如果某个节点的入度减为0，则将其加入队列中。
		while (!queue.isEmpty()) {
			String curId = queue.poll();
			List<String> nextIds = map.getOrDefault(curId, new ArrayList<>());
			for (String nextId : nextIds) {
				hashMap.put(nextId, hashMap.getOrDefault(nextId, 0) - 1);
				if (hashMap.getOrDefault(nextId, 0) == 0) {
					queue.offer(nextId);
				}
			}
		}

		// 3.最后，判断是否存在入度不为0的节点，如果存在则说明存在环，否则不存在
		for (String key : hashMap.keySet()) {
			if (hashMap.getOrDefault(key, 0) != 0){
				// 存在环
				return false;
			}
		}
		// 不存在环
		return true;
	}


	/**
	 * 删除节点连线
	 *
	 * @param confGraph
	 * @return 通用返回对象
	 */
	@Override
	@Transactional(rollbackFor = Exception.class)
	public R<String> removeLink(ConfGraph confGraph) {
		LambdaUpdateWrapper<ConfGraph> updateWrapper = Wrappers.lambdaUpdate();
		updateWrapper.eq(ConfGraph::getType, GraphType.IT_ROAD_RELATIONSHIP.getType())
					 .eq(ConfGraph::getGraphId, String.valueOf(confGraph.getSystemId()))
					 .eq(ConfGraph::getNodeId, String.valueOf(confGraph.getNodeId()))
				 	 .eq(ConfGraph::getParentNodeId, String.valueOf(confGraph.getParentNodeId()));
		return R.ok(confGraphService.remove(updateWrapper) ? "删除节点成功": "删除节点失败");
	}

	/**
	 * 删除节点
	 *
	 * @param confSegment
	 * @return 通用返回对象
	 */
	@Override
	@Transactional(rollbackFor = Exception.class)
	public R<String> removeNode(ConfSegment confSegment) {
		// 1. 删除网端
		confSegmentService.removeById(confSegment);
		// 2. 删除组件ip
		LambdaUpdateWrapper<ConfComponentIp> lambdaUpdateWrapper = Wrappers.lambdaUpdate();
		lambdaUpdateWrapper.eq(ConfComponentIp::getSegmentId, confSegment.getId());
		confComponentIpService.remove(lambdaUpdateWrapper);

		// 3. 删除网端的端到端的关系
		LambdaUpdateWrapper<ConfGraph> lambdaUpdate = Wrappers.lambdaUpdate();
		lambdaUpdate.eq(ConfGraph::getType, GraphType.IT_ROAD_RELATIONSHIP.getType())
					.eq(ConfGraph::getGraphId, confSegment.getSystemId())
					.eq(ConfGraph::getNodeId, confSegment.getId())
					.and(s -> s.eq(ConfGraph::getParentNodeId, confSegment.getId()).or().eq(ConfGraph::getNodeId, confSegment.getId()));

		confGraphService.remove(lambdaUpdate);

		// 4. 删除节点的信息
		LambdaUpdateWrapper<ConfNodeProperty> updateWrapper = Wrappers.lambdaUpdate();
		updateWrapper.eq(ConfNodeProperty::getType, GraphType.IT_ROAD_RELATIONSHIP.getType())
					 .eq(ConfNodeProperty::getGraphId, confSegment.getSystemId())
					 .eq(ConfNodeProperty::getNodeId, confSegment.getId());
		confNodePropertyService.remove(updateWrapper);
		return R.ok("删除节点成功");
	}

	/**
	 * 节点移动位置
	 *
	 * @param confNodeProperty
	 * @return 通用返回对象
	 */
	@Override
	public R<String> setLocation(ConfNodeProperty confNodeProperty) {
		LambdaUpdateWrapper<ConfNodeProperty> updateWrapper = Wrappers.lambdaUpdate();
		updateWrapper.eq(ConfNodeProperty::getType, GraphType.IT_ROAD_RELATIONSHIP.getType())
					 .eq(ConfNodeProperty::getGraphId, confNodeProperty.getSystemId())
					 .eq(ConfNodeProperty::getNodeId, confNodeProperty.getNodeId())
					 .set(ConfNodeProperty::getLocationX, confNodeProperty.getLocationX())
					 .set(ConfNodeProperty::getLocationY, confNodeProperty.getLocationY());
		confNodePropertyService.update(updateWrapper);
		return R.ok("移动节点坐标位置成功");
	}

	/**
	 * 供网端监控详情 远程调用的 it路径图接口
	 *
	 * @param confNodeProperty
	 * @return 通用返回对象
	 */
	@Override
	public List<Map<String, Object>> segmentMonitorDetailItRoadGraph(ConfNodeProperty confNodeProperty) {
		// 1. 获取网端信息
		QueryWrapper<ConfSegment> queryWrapper = new QueryWrapper<>();
		queryWrapper.eq("system_id", confNodeProperty.getSystemId());
		Map<Integer, String> confSegmentsMap = confSegmentService.list(queryWrapper).stream().collect(Collectors.toMap(ConfSegment::getId, ConfSegment::getName));

		// 2. 获取节点关系信息
		QueryWrapper<ConfGraph> queryWrapperGraph = new QueryWrapper<>();
		queryWrapperGraph.eq("graph_id", confNodeProperty.getSystemId());
		queryWrapperGraph.eq("type", GraphType.IT_ROAD_RELATIONSHIP.getType());
		List<ConfGraph> confGraphs = confGraphService.list(queryWrapperGraph);


		// 3. 获取节点坐标等信息  提供在bpm 的坐标
		LambdaQueryWrapper<ConfNodeProperty> propertyLambdaQueryWrapper = Wrappers.lambdaQuery();
		propertyLambdaQueryWrapper.eq(ConfNodeProperty::getType, confNodeProperty.getType());
		propertyLambdaQueryWrapper.eq(ConfNodeProperty::getGraphId, confNodeProperty.getGraphId());
		Map<String, ConfNodeProperty> nodePropertyIdAndObjectMap = confNodePropertyService.list(propertyLambdaQueryWrapper).stream().collect(Collectors.toMap(ConfNodeProperty::getNodeId, v -> v, (k1, k2) -> k2));

		//
		LambdaQueryWrapper<ConfNodeProperty> realPropertyLambdaQueryWrapper = Wrappers.lambdaQuery();
		realPropertyLambdaQueryWrapper.eq(ConfNodeProperty::getType,  GraphType.IT_ROAD_RELATIONSHIP.getType());
		realPropertyLambdaQueryWrapper.eq(ConfNodeProperty::getGraphId, confNodeProperty.getGraphId());
		Map<String, ConfNodeProperty> realNodePropertyIdAndObjectMap = confNodePropertyService.list(realPropertyLambdaQueryWrapper).stream().collect(Collectors.toMap(ConfNodeProperty::getNodeId, v -> v, (k1, k2) -> k2));

		// 将上面信息组装成 多节点的树结构, 返回给前端
		return generateRoadMap(confSegmentsMap, confGraphs, nodePropertyIdAndObjectMap, realNodePropertyIdAndObjectMap);
	}

	/**
	 * 获取服务资源
	 *
	 * @param confSegmentResourceRelation
	 * @return 通用返回对象
	 */
	@Override
	public Page<Map<String,Object>> getComponentServerResources(ConfSegmentResourceRelation confSegmentResourceRelation) {
		return segmentResourceRelationService.listPage(confSegmentResourceRelation);
	}

	/**
	 * 添加组件资源
	 *
	 * @param confSegmentResourceRelation
	 * @return 通用返回对象
	 */
	@Override
	public R<String> addComponent(ConfSegmentResourceRelation confSegmentResourceRelation) {

		// 1、判断同系统、同网端是否存在相同的服务资源，已经存在则不进行新增
		if (judgeIsSameServiceResource(confSegmentResourceRelation)) {
			return R.failed("网端组件服务资源已存在");
		}

		// 2、检查同系统中是否存在以编辑后的url为前缀的服务资源(子字符串)，若存在提示"该服务资源已存在于**系统、**网端上"
		List<ConfSegmentResourceRelation> list = segmentResourceRelationService.checkPrefixUrlExsit(confSegmentResourceRelation);
		if (!CollectionUtils.isEmpty(list)){
			ConfSegmentResourceRelation resourceRelation = list.get(0);
			ConfSystem confSystem = confSystemService.getById(resourceRelation.getSystemId());
			ConfSegment confSegment = confSegmentService.getById(resourceRelation.getSegmentId());
			return R.failed("确认失败，" + resourceRelation.getResourceStr() + "已确认到" + confSystem.getName() + "系统" + confSegment.getName() + "网端，如需添加，请先删除");
		}

		// 3、新增IT路径组件服务资源
		insertConfSegmentResourceRelation(confSegmentResourceRelation);

		// 4.1、编辑后的IT路径组件服务资源url精确匹配未确认服务资源原始url
		List<ConfUnconfirmedUrl> unconfirmedUrls = getUnconfirmedUrls(confSegmentResourceRelation);

		// 5、查询同url、不同网端的已确认服务资源，若存在，复制到本网端(相当于自动再次确认)
		List<ConfConfirmedUrl> confirmedUrls = getConfConfirmedUrls(confSegmentResourceRelation);

		if (CollectionUtils.isEmpty(unconfirmedUrls) && CollectionUtils.isEmpty(confirmedUrls)) {
			// 新增成功，无自动确认的未确认服务资源，无自动再次确认的已确认服务资源
			// return result.setFail(Result.FAIL,
			// "新增成功，无自动确认的未确认服务资源，无自动再次确认的已确认服务资源");
			return R.ok();
		}

		// 6、将未确认服务资源进行确认，移到已确认服务资源表中
		List<Long> unConfirmedResourceIds = new ArrayList<>();
		List<ConfConfirmedUrl> confirmedResourceList = getConfirmedResourceList(unconfirmedUrls,
				unConfirmedResourceIds, confSegmentResourceRelation);

		if (!CollectionUtils.isEmpty(confirmedResourceList)) {
			if (!confConfirmedUrlService.saveBatch(confirmedResourceList)) {
				// 写入已确认服务资源表中失败
				return R.failed("写入已确认服务资源表中失败");
			}
		}

		// 7、将已确认服务资源进行再次确认
		confirmedResourceList = doubleCheckConfirmResource(confirmedUrls, confSegmentResourceRelation);
		if (!confConfirmedUrlService.saveBatch(confirmedResourceList)) {
				// 写入已确认服务资源表中失败
				return R.failed("写入已确认服务资源表中失败");
		}

		// 8、删除未确认服务资源
		if (!CollectionUtils.isEmpty(unConfirmedResourceIds)) {
			if (!unconfirmedUrlService.removeBatchByIds(unConfirmedResourceIds)) {
				// 删除未确认服务资源失败
				return R.failed("删除未确认服务资源失败");
			}
		}
		return R.ok();
	}

	private boolean judgeIsSameServiceResource(ConfSegmentResourceRelation confSegmentResourceRelation) {
		LambdaQueryWrapper<ConfSegmentResourceRelation> queryWrapper = Wrappers.lambdaQuery();
		queryWrapper.eq(ConfSegmentResourceRelation::getSystemId, confSegmentResourceRelation.getSystemId())
				.eq(ConfSegmentResourceRelation::getSegmentId, confSegmentResourceRelation.getSegmentId())
				.eq(ConfSegmentResourceRelation::getResourceStr, confSegmentResourceRelation.getResourceStr());

		return segmentResourceRelationService.count(queryWrapper) > 0;
	}

	private void insertConfSegmentResourceRelation(ConfSegmentResourceRelation confSegmentResourceRelation) {
		confSegmentResourceRelation.setCreateBy(SecurityUtils.getUser().getName());
		confSegmentResourceRelation.setCreateTime(LocalDateTime.now());
		confSegmentResourceRelation.setIsDel(0);
		confSegmentResourceRelation.setType(1);
		segmentResourceRelationService.save(confSegmentResourceRelation);
	}

	private List<ConfUnconfirmedUrl> getUnconfirmedUrls (ConfSegmentResourceRelation confSegmentResourceRelation) {
		List<ConfUnconfirmedUrl> unconfirmedUrls = new ArrayList<>();
		List<ConfUnconfirmedUrl> dataList = unconfirmedUrlService.list(new LambdaQueryWrapper<ConfUnconfirmedUrl>()
				.eq(ConfUnconfirmedUrl::getOriUrl, confSegmentResourceRelation.getResourceStr()));

		unconfirmedUrls.addAll(dataList);
		unconfirmedUrls.addAll(unconfirmedUrlService.prefixUrlMatch(confSegmentResourceRelation));

		return unconfirmedUrls;
	}

	private List<ConfConfirmedUrl> getConfConfirmedUrls(ConfSegmentResourceRelation confSegmentResourceRelation) {
		return confConfirmedUrlService.list(new LambdaQueryWrapper<ConfConfirmedUrl>()
				.eq(ConfConfirmedUrl::getSegmentId, confSegmentResourceRelation.getSegmentId())
				.eq(ConfConfirmedUrl::getConfirmedUrl, confSegmentResourceRelation.getResourceStr()));
	}

	private List<ConfConfirmedUrl> getConfirmedResourceList(List<ConfUnconfirmedUrl> unconfirmedUrls, List<Long> unConfirmedResourceIds,
															ConfSegmentResourceRelation confSegmentResourceRelation) {
		List<ConfConfirmedUrl> confirmedResourceList = new ArrayList<>();

		unconfirmedUrls.forEach(ur -> {
			unConfirmedResourceIds.add(Long.valueOf(ur.getId()));
			ConfConfirmedUrl confConfirmedUrl = new ConfConfirmedUrl();
			confConfirmedUrl.setResourceCode(ur.getResourceCode());
			confConfirmedUrl.setPrefixUrl(ur.getPrefixUrl());
			confConfirmedUrl.setOriUrl(ur.getOriUrl());
			confConfirmedUrl.setConfirmedUrl(confSegmentResourceRelation.getResourceStr());
			confConfirmedUrl.setStatus(0); // 0: 前缀URL
			confConfirmedUrl.setSystemId(confSegmentResourceRelation.getSystemId());
			confConfirmedUrl.setSegmentId(confSegmentResourceRelation.getSegmentId());
			confConfirmedUrl.setResourceComponentId(confSegmentResourceRelation.getId());
			confirmedResourceList.add(confConfirmedUrl);
		});

		return confirmedResourceList;
	}

	private List<ConfConfirmedUrl> doubleCheckConfirmResource(List<ConfConfirmedUrl> confirmedUrls,
															  ConfSegmentResourceRelation confSegmentResourceRelation) {
		List<ConfConfirmedUrl> confirmedResourceList = new ArrayList<>();
		List<String> distinctUrl = new ArrayList<>(); // originalUrl去重
		confirmedUrls.forEach(cr -> {
			String originalUrl = cr.getOriUrl();
			if (!distinctUrl.contains(originalUrl)) {
				ConfConfirmedUrl confirmedResource = new ConfConfirmedUrl();
				confirmedResource.setResourceCode(cr.getResourceCode());
				confirmedResource.setPrefixUrl(cr.getPrefixUrl());
				confirmedResource.setOriUrl(cr.getOriUrl());
				confirmedResource.setConfirmedUrl(cr.getConfirmedUrl());
				confirmedResource.setStatus(cr.getStatus());
				confirmedResource.setSystemId(confSegmentResourceRelation.getSystemId());
				confirmedResource.setSegmentId(confSegmentResourceRelation.getSystemId());
				confirmedResource.setResourceComponentId(confSegmentResourceRelation.getId());
				confirmedResourceList.add(confirmedResource);
				distinctUrl.add(originalUrl);
			}
		});

		return confirmedResourceList;
	}

	/**
	 * 删除组件资源
	 *
	 * @param ids
	 * @return 通用返回对象
	 */
	@Override
	public R<String> deleteComponentResourceByIds(List<Integer> ids) {
		List<Integer> itResourceIds = new ArrayList<>();
		for (Integer id : ids) {
			// 1、先查询出这条IT端组件服务资源
			ConfSegmentResourceRelation confSegmentResourceRelation = segmentResourceRelationService.getById(id);
			if (confSegmentResourceRelation == null) {
				// IT端组件服务资源不存在
				return R.failed("网端端组件服务资源不存在");
			}
			itResourceIds.add(id);

			// 2、查询对应系统、网端、已确认url一致的已确认服务资源
			LambdaQueryWrapper<ConfConfirmedUrl> queryWrapper = Wrappers.lambdaQuery();
			queryWrapper.eq(ConfConfirmedUrl::getSystemId, confSegmentResourceRelation.getSystemId())
						.eq(ConfConfirmedUrl::getSegmentId, confSegmentResourceRelation.getSegmentId())
						.eq(ConfConfirmedUrl::getConfirmedUrl, confSegmentResourceRelation.getResourceStr());
			List<ConfConfirmedUrl> confConfirmedUrls = confConfirmedUrlService.list(queryWrapper);

			// 3、更新业务服务资源为未使用，供数据重组重新发现
			List<Integer> deleteIds = confConfirmedUrls.stream().map(ConfConfirmedUrl::getId).collect(Collectors.toList());

			// 更新业务服务资源为未使用，用网端服务资源url模糊匹配
			confResourceService.updateBusinessResourceNoUsed(confSegmentResourceRelation.getResourceStr());

			// 4、批量删除已确认服务资源
			if (!CollectionUtils.isEmpty(deleteIds)) {
				if (confConfirmedUrlService.removeBatchByIds(deleteIds)) {
					// 删除已确认服务资源失败
					return R.failed("删除已确认服务资源失败");
				}
			}
		}

		// 5、批量删除IT端组件服务资源
		if (!CollectionUtils.isEmpty(itResourceIds)) {
			if (segmentResourceRelationService.removeBatchByIds(itResourceIds)) {
				// 删除IT路径组件服务资源失败
				return R.failed("删除IT路径组件服务资源失败");
			}
		}
		return R.ok();
	}

	/**
	 * 修改网端节点
	 *
	 * @param itRoadVo
	 * @return 通用返回对象
	 */
	@Override
	public R<String> updateNodeById(ITRoadVo itRoadVo) {
		ConfSegment confSegment = new ConfSegment();
		BeanUtils.copyProperties(itRoadVo, confSegment);
		confSegment.setUpdateBy(SecurityUtils.getUser().getName());
		confSegment.setUpdateTime(LocalDateTime.now());

		boolean flag = confSegmentService.updateById(confSegment);
		if (!flag) {
			return R.failed("更新失败");
		}

		return R.ok("更新成功");
	}


	/**
	 * 生成IT路径图
	 * @param confGraphs        节点之间的关系
	 * @param confSegmentsMap  网端id 和 网端信息之间映射
	 * @param nodePropertyIdAndObjectMap
	 * @return 返回通用对象
	 */
	private List<Map<String, Object>> generateRoadMap(Map<Integer, String> confSegmentsMap, List<ConfGraph> confGraphs, Map<String, ConfNodeProperty> nodePropertyIdAndObjectMap, Map<String, ConfNodeProperty> realNodePropertyIdAndObjectMap) {
		// 构建 父节点 和 子节点一对多关系
		Map<String, List<ConfGraph>> confGraphMap = new HashMap<>();
		for (ConfGraph confGraph : confGraphs) {
			confGraphMap.computeIfAbsent(confGraph.getParentNodeId(), k -> new ArrayList<>()).add(confGraph);
		}

		Set<String> headNodes = new HashSet<>();

		Map<String, Map<String, Object>> map = new HashMap<>();
		List<String> parentNodeIds = confGraphs.stream().map(ConfGraph::getParentNodeId).collect(Collectors.toList());
		for (ConfGraph node : confGraphs) {
			// 找出根节点
			if (!parentNodeIds.contains(node.getNodeId())) {
				headNodes.add(node.getParentNodeId());
			}
			String prev = node.getParentNodeId();
			String cur = node.getNodeId();
			Map<String, Object> treeNode = null;
			treeNode = map.getOrDefault(cur, getTreeNodeInfo(confSegmentsMap, nodePropertyIdAndObjectMap, cur));
			Map<String, Object> parentNode = map.getOrDefault(prev,getTreeNodeInfo(confSegmentsMap, nodePropertyIdAndObjectMap, prev));
			List<Map<String, Object>> childNodes = (List<Map<String, Object>>) parentNode.computeIfAbsent("childNodes", k -> new ArrayList<>());
			childNodes.add(treeNode);
			map.put(prev, parentNode);
			map.put(cur, treeNode);
		}
		List<Map<String, Object>> treeNodes = new ArrayList<>();
		for (String nodeId : realNodePropertyIdAndObjectMap.keySet()) {
			if(!headNodes.contains(nodeId)){
				if (map.containsKey(nodeId)){
					treeNodes.add(map.get(nodeId));
				}else {
					treeNodes.add(getTreeNodeInfo(confSegmentsMap, nodePropertyIdAndObjectMap, nodeId));
				}
			}
		}
		log.info("[配置系统IT路径图] 返回的结果: {}", treeNodes.toString());
		return treeNodes;
	}

	/**
	 *
	 * @param confSegmentsMap
	 * @param nodePropertyIdAndObjectMap
	 * @param cur
	 * @return
	 */
	private Map<String, Object> getTreeNodeInfo(Map<Integer, String> confSegmentsMap, Map<String, ConfNodeProperty> nodePropertyIdAndObjectMap, String cur) {
		Map<String, Object> treeNode = new HashMap<>();
		treeNode.put("id", Integer.valueOf(cur));
		treeNode.put("segmentId", Integer.valueOf(cur));
		treeNode.put("SegmentName", confSegmentsMap.get(Integer.valueOf(cur)));
		if (nodePropertyIdAndObjectMap.get(cur) != null) {
			treeNode.put("locationX",nodePropertyIdAndObjectMap.get(cur).getLocationX());
			treeNode.put("locationY", nodePropertyIdAndObjectMap.get(cur).getLocationY());
		}
		return treeNode;
	}


	/**
	 * 生成IT路径图
	 * @param confComponentIps  ip和port 信息
	 * @param confSegmentResourceRelations  资源url
	 * @param confGraphs        节点之间的关系
	 * @param confSegmentsMap  网端id 和 网端信息之间映射
	 * @param nodePropertyIdAndObjectMap
	 * @return 返回通用对象
	 */
	private List<Map<String, Object>> generateRoadMap(List<ConfComponentIp> confComponentIps,
													  List<ConfGraph> confGraphs, Map<Integer, String> confSegmentsMap,
													  Map<String, ConfNodeProperty> nodePropertyIdAndObjectMap,
													  Integer systemId) {
		// 构建 组件与 网端之间 一对多关系
		Map<Integer, List<ConfComponentIp>> confComponentIpMap = new HashMap<>();
		for (ConfComponentIp confComponentIp : confComponentIps) {
			confComponentIpMap.computeIfAbsent(confComponentIp.getSegmentId(), k -> new ArrayList<>()).add(confComponentIp);
		}
		// 存储作为子节点的节点容器
		Set<String> childNodeSet = new HashSet<>();
		Map<String, Map<String, Object>> map = new HashMap<>();
		for (ConfGraph node : confGraphs) {
			// 记录那些节点是作为子节点
			childNodeSet.add(node.getNodeId());
			String prev = node.getParentNodeId();
			String cur = node.getNodeId();
			Map<String, Object> treeNode = null;

			// 判断节点存在  map 集合里面，如果没有，则生成一个节点对象
			treeNode = map.getOrDefault(cur, getTreeNodeInfo(confSegmentsMap, nodePropertyIdAndObjectMap, confComponentIpMap, cur, systemId));
			Map<String, Object> parentNode = map.getOrDefault(prev,getTreeNodeInfo(confSegmentsMap, nodePropertyIdAndObjectMap, confComponentIpMap, prev, systemId));

			// 记录父节点下的子节点信息
			List<Map<String, Object>> childNodes = (List<Map<String, Object>>) parentNode.computeIfAbsent("childNodes", k -> new ArrayList<>());
			childNodes.add(treeNode);

			// 记录下每一个节点ID 对应的节点对象
			map.put(prev, parentNode);
			map.put(cur, treeNode);
		}

		//找出 IT 路径图的 头节点,  childNodeSet 记录作为子字节的节点,  nodePropertyIdAndObjectMap.keySet() 记录了改系统的IT路径图所有的节点
		List<Map<String, Object>> headerNodes = new ArrayList<>();
		for (String nodeId : nodePropertyIdAndObjectMap.keySet()) {
			// 该节点不是作为子字点,所以该节点就是父节点
			if(!childNodeSet.contains(nodeId)){
				// 判断节点容器中是否有该节点的信息
				if (map.containsKey(nodeId)){
					headerNodes.add(map.get(nodeId));
				}else {
					headerNodes.add(getTreeNodeInfo(confSegmentsMap, nodePropertyIdAndObjectMap, confComponentIpMap, nodeId, systemId));
				}
			}
		}
		return headerNodes;
	}

	/**
	 * 填充节点的各种属性
	 *
	 * @param confSegmentsMap
	 * @param nodePropertyIdAndObjectMap
	 * @param confComponentIpMap
	 * @param cur
	 * @return
	 */
	private Map<String, Object> getTreeNodeInfo(Map<Integer, String> confSegmentsMap,
												Map<String, ConfNodeProperty> nodePropertyIdAndObjectMap,
												Map<Integer, List<ConfComponentIp>> confComponentIpMap,
												String cur,
												Integer systemId) {
		Map<String, Object> treeNode = new HashMap<>();
		if (confComponentIpMap.containsKey(Integer.valueOf(cur))) {
			treeNode.put("ipAndPort", confComponentIpMap.get(Integer.valueOf(cur)).stream().map(componentIp -> componentIp.getIp() + " : " + componentIp.getPort()).collect(Collectors.toList()));
		}
		treeNode.put("id", Integer.valueOf(cur));
		treeNode.put("segmentId", Integer.valueOf(cur));
		treeNode.put("SegmentName", confSegmentsMap.get(Integer.valueOf(cur)));
		if (nodePropertyIdAndObjectMap.get(cur) != null) {
			treeNode.put("locationX",nodePropertyIdAndObjectMap.get(cur).getLocationX());
			treeNode.put("locationY", nodePropertyIdAndObjectMap.get(cur).getLocationY());
		}

		QueryWrapper<ConfComponentIp> queryWrapper = new QueryWrapper<>();
		queryWrapper.eq("segment_id", Integer.valueOf(cur));
		queryWrapper.eq("system_id", systemId);
		List<String> ipAndPorts = confComponentIpService.list(queryWrapper).stream().map(s -> s.getIp() + s.getPort()).collect(Collectors.toList());

		QueryWrapper<ConfComponentResource> componentResourceQueryWrapper = new QueryWrapper<>();
		componentResourceQueryWrapper.eq("segment_id", Integer.valueOf(cur));
		componentResourceQueryWrapper.eq("system_id", systemId);
		List<String> urls = confComponentResourceService.list(componentResourceQueryWrapper).stream().map(ConfComponentResource::getIdentifyStr).collect(Collectors.toList());
		treeNode.put("urls", urls);
//		treeNode.put("ipAndPorts", ipAndPorts);
		return treeNode;
	}

}
